﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using JEdwonTune.Lib;
using JEdwonTune.Validation;
using JEdwonTune.Crud;
using JEdwonTune.Authentication;

namespace JEdwonTune.Common {
    public partial class FrmXmlEditor : FrmMDIChild {
        public FrmXmlEditor() {
            InitializeComponent();
        }

        #region 属性定义
        private String _FilePath;
        public String FilePath {
            set { _FilePath = value; }
            get { return _FilePath; }
        }

        private XmlDocument _Doc;
        public XmlDocument Doc {
            set { _Doc = value; }
            get { return _Doc; }
        }

        private XmlEditorTarget _Target;
        public XmlEditorTarget Target {
            set { _Target = value; }
            get { return _Target; }
        }

        private String _NameSpace = null;

        private TreeNode _CopiedTn = null;
        private XmlNode _CopiedXn = null;

        ToolStripItem tsiAddModel = null;
        ToolStripItem tsiAddCrudProperty = null;
        ToolStripItem tsiAddDatasource = null;
        ToolStripItem tsiImportEO = null;
        
        ToolStripItem tsiAddVdForm = null;
        ToolStripItem tsiAddVdField = null;

        ToolStripItem tsiAddRole = null;
        ToolStripItem tsiAddOperation = null;

        private Boolean _ContentChanged = false;
        #endregion

        private void FrmXmlEditor_Load(object sender, EventArgs e) {
            Boolean InitSucceed = Init();
            if (InitSucceed) {
                BindDoc2Tree();
            }
        }

        #region 内部方法

        private Boolean Init() {
            if (_Doc == null) {
                MessageBox.Show("没有为文档对象Doc赋值", "初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                this.Close();
                return false;
            }
            _NameSpace = _Doc.DocumentElement.NamespaceURI;
            switch (_Target) {
                case XmlEditorTarget.CrudConfig:
                    tsiAddModel = this.tsbtnAdd.DropDownItems.Add("增加Model节点", null, new EventHandler(AddModelNode_Click));
                    tsiAddCrudProperty = this.tsbtnAdd.DropDownItems.Add("增加Property节点", null, new EventHandler(AddCrudPropertyNode_Click));
                    tsiAddDatasource = this.tsbtnAdd.DropDownItems.Add("增加Datasource节点", null, new EventHandler(AddDatasourceNode_Click));
                    tsiImportEO = this.tsbtnAdd.DropDownItems.Add("导入实体类", null, new EventHandler(ImportEO_Click));
                    break;
                case XmlEditorTarget.VdConfig:
                    tsiAddVdForm = this.tsbtnAdd.DropDownItems.Add("增加Form节点", null, new EventHandler(AddVdForm_Click));
                    tsiAddVdField = this.tsbtnAdd.DropDownItems.Add("增加Field节点", null, new EventHandler(AddVdField_Click));
                    break;
                case XmlEditorTarget.Authentication:
                    tsiAddRole = this.tsbtnAdd.DropDownItems.Add("增加Role节点", null, new EventHandler(AddAuthRole_Click));
                    tsiAddOperation = this.tsbtnAdd.DropDownItems.Add("增加Operation节点", null, new EventHandler(AddAuthOperation_Click));
                    break;
                default:
                    MessageBox.Show("没有为Target对象赋值", "初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return false;
            }
            this.tsbtnSave.Enabled = false;
            return true;
        }
        private void BindDoc2Tree() {
            this.tvDoc.Nodes.Clear();
            XmlHelper.BindXml2TreeView(_Doc, ref tvDoc);
            tvDoc.Refresh();
            tvDoc.ExpandAll();
            tvDoc.Select();
        }
        private void SetButtonStatus(String nodeName) {
            if (_Target == XmlEditorTarget.CrudConfig) {
                this.tsiAddModel.Enabled = (nodeName == "models");
                this.tsiAddCrudProperty.Enabled = (nodeName == "model");
                this.tsiAddDatasource.Enabled = (nodeName == "datasource");
                this.tsbtnMoveDown.Enabled = this.tsbtnMoveUp.Enabled = (nodeName == "property");
                this.tsbtnEdit.Enabled = this.tsbtnDelete.Enabled = this.tsbtnCopy.Enabled = this.tsbtnPaste.Enabled = (nodeName == "property"
                    || nodeName == "model" || nodeName == "resource");
            } else if (_Target == XmlEditorTarget.VdConfig) {
                this.tsiAddVdForm.Enabled = (nodeName == "validation");
                this.tsiAddVdField.Enabled = (nodeName == "form");
                this.tsbtnMoveDown.Enabled = this.tsbtnMoveUp.Enabled = (nodeName == "field");
                this.tsbtnEdit.Enabled = this.tsbtnDelete.Enabled = this.tsbtnCopy.Enabled = this.tsbtnPaste.Enabled = (nodeName == "form"
                    || nodeName == "field" );
            } else if (_Target == XmlEditorTarget.Authentication) {
                this.tsiAddRole.Enabled = (nodeName == "roles");
                this.tsiAddOperation.Enabled = (nodeName == "operations");
                this.tsbtnEdit.Enabled = this.tsbtnDelete.Enabled = this.tsbtnCopy.Enabled = this.tsbtnPaste.Enabled = (nodeName == "role"
                    || nodeName == "operation" );
            }
        }
        private void OnContentChanged() {
            if (_ContentChanged) return;
            this.tsbtnSave.Enabled = true;
            _ContentChanged = true;
        }
        private void OnContentSaved() {
            this.tsbtnSave.Enabled = false;
            _ContentChanged = false;
        }
        private void RefreshXmlCodeView(XmlNode n) {
            this.rtxtCodeView.Text = n.OuterXml;
        }
        private void RefreshTreeNode(XmlNode xn, ref TreeNode tn) {
            tn.Text = XmlHelper.GetTreeNodeTitle(xn);
            RefreshXmlCodeView(xn);
            this.tvDoc.Refresh();
        }
        private String GetDefaultFileName() {
            if (_Target == XmlEditorTarget.CrudConfig)
                return "Crud.config";
            else if (_Target == XmlEditorTarget.VdConfig)
                return "Validation.config";
            else if (_Target == XmlEditorTarget.HbMapping)
                return "NewFile.hbm.xml";
            else
                return "unknown.config";
        }
        private String GetDefaultTitle() {
            if (_Target == XmlEditorTarget.CrudConfig)
                return "编辑Crud配置:"+_FilePath;
            else if (_Target == XmlEditorTarget.VdConfig)
                return "编辑Validation配置:" + _FilePath;
            else if (_Target == XmlEditorTarget.HbMapping)
                return "编辑Mapping:" + _FilePath;
            else
                return "编辑unknown:" + _FilePath;
        }
        private TreeNode AddNewTreeNode(XmlNode xn, ref TreeNode tn) {
            TreeNode newtn = new TreeNode();
            newtn.Text = XmlHelper.GetTreeNodeTitle(xn);
            newtn.Tag = xn;
            tn.Nodes.Add(newtn);
            RefreshXmlCodeView(xn);
            this.tvDoc.Refresh();
            return newtn;
        }
        private XmlElement BuildNewElement(String name) {
            if(String.IsNullOrEmpty(_NameSpace))
                return _Doc.CreateElement(name);
            else
                return _Doc.CreateElement(name, _NameSpace);
        }

        #endregion 


        #region 事件处理
        
        #region CRUD的相关事件
        /// <summary>
        /// 增加model节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddModelNode_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditModel();
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("model");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
        }
        /// <summary>
        /// 增加property节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddCrudPropertyNode_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditProperty();
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("property");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
        }
        /// <summary>
        /// 增加Datasource节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddDatasourceNode_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditResource();
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("resource");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
        }
        /// <summary>
        /// 导入实体类
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void ImportEO_Click(Object sender, EventArgs e) {
            FrmImportDll frm = new FrmImportDll();
            frm.Doc = _Doc;
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                BindDoc2Tree();
                this.OnContentChanged();
            }
        }
        #endregion

        #region Validation相关事件
        /// <summary>
        /// 增加Field节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddVdField_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditField();
            frm.TheParent = xn;
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("field");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
            this.OnContentChanged();
        }
        /// <summary>
        /// 增加Form节点
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void AddVdForm_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditForm();
            frm.TheParent = xn;
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("form");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
            this.OnContentChanged();
        }
        #endregion

        #region Authentication相关事件
        protected void AddAuthRole_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditRole();
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("role");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
            this.OnContentChanged();
        }
        protected void AddAuthOperation_Click(Object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmEditOperation();
            frm.Doc = _Doc;
            frm.Node = BuildNewElement("operation");
            DialogResult dr = frm.ShowDialog();
            if (dr == DialogResult.OK) {
                XmlNode newNode = xn.AppendChild(frm.Node);
                TreeNode ntn = AddNewTreeNode(newNode, ref tn);
                this.tvDoc.SelectedNode = ntn;
                this.tvDoc.Select();
                this.OnContentChanged();
            }
            this.OnContentChanged();
        }
        #endregion

        #region 通用的菜单事件
        private void tsbtnSave_Click(object sender, EventArgs e) {
            if (String.IsNullOrEmpty(FilePath)) {
                saveFileDialog1.AddExtension = true;
                saveFileDialog1.Filter = "配置文件(*.config)|*.config|XML文件(*.xml)|*.xml|所有文件(*.*)|*.*";
                saveFileDialog1.DefaultExt = ".config";
                saveFileDialog1.FileName = GetDefaultFileName();
                DialogResult dr = saveFileDialog1.ShowDialog();
                if (dr == DialogResult.OK) {
                    _FilePath = saveFileDialog1.FileName;
                    this.Text = GetDefaultTitle();
                } else {
                    return;
                }
            }
            try {
                _Doc.Save(_FilePath);
                this.OnContentSaved();
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }
        private void tsbtnSaveAs_Click(object sender, EventArgs e) {
            saveFileDialog1.AddExtension = true;
            saveFileDialog1.Filter = "配置文件(*.config)|*.config|XML文件(*.xml)|*.xml|所有文件(*.*)|*.*";
            saveFileDialog1.DefaultExt = ".config";
            saveFileDialog1.FileName = GetDefaultFileName();
            DialogResult dr = saveFileDialog1.ShowDialog();
            if (dr == DialogResult.OK) {
                _FilePath = saveFileDialog1.FileName;
                this.Text = GetDefaultTitle();
            } else {
                return;
            }
            try {
                _Doc.Save(_FilePath);
                this.OnContentSaved();
            } catch (Exception ex) {
                MessageBox.Show(ex.Message);
            }
        }
        private void tsbtnEdit_Click(object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            FrmXmlNodeEditorBase frm = new FrmXmlNodeEditorBase();
            if (_Target == XmlEditorTarget.CrudConfig) {
                if (xn.Name == "model") {
                    frm = new FrmEditModel();
                } else if (xn.Name == "property") {
                    frm = new FrmEditProperty();
                } else if (xn.Name == "resource") {
                    frm = new FrmEditResource();
                } else {
                    return;
                }
            } else if (_Target == XmlEditorTarget.VdConfig) {
                if (xn.Name == "form") {
                    frm = new FrmEditForm();
                } else if (xn.Name == "field") {
                    frm = new FrmEditField();
                } else {
                    return;
                }
            }
            frm.TheParent = xn.ParentNode;
            frm.Doc = _Doc;
            frm.Node = xn;
            DialogResult dr = frm.ShowDialog();
            if (frm.DialogResult == DialogResult.OK) {
                xn.ParentNode.ReplaceChild(frm.Node, xn);
                RefreshTreeNode(frm.Node, ref tn);
                this.OnContentChanged();
            }
            frm.Dispose();
        }

        private void tsbtnDelete_Click(object sender, EventArgs e) {
            if (MessageBox.Show("确定要删除该节点？", "删除确认", MessageBoxButtons.OKCancel) == DialogResult.OK) {
                TreeNode tn = this.tvDoc.SelectedNode;
                XmlNode xn = (XmlNode)tn.Tag;
                try {
                    xn.ParentNode.RemoveChild(xn);
                } catch (Exception ex) {
                    MessageBox.Show(ex.Message);
                    return;
                }
                tn.Remove();
                this.OnContentChanged();
            }
        }

        private void tsbtnMoveUp_Click(object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            if (tn.Index == 0) return;
            xn.ParentNode.InsertBefore(xn, xn.PreviousSibling);
            TreeNode newtn = (TreeNode)tn.Clone();
            tn.Parent.Nodes.Insert(tn.Index - 1, newtn);
            newtn.Parent.Nodes.Remove(tn);
            this.tvDoc.Refresh();
            this.tvDoc.SelectedNode = newtn;
            this.tvDoc.Select();
            this.OnContentChanged();
        }

        private void tsbtnMoveDown_Click(object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            if (tn.Index >= tn.Parent.Nodes.Count - 1) return;
            xn.ParentNode.InsertAfter(xn, xn.NextSibling);
            TreeNode newtn = (TreeNode)tn.Clone();
            tn.Parent.Nodes.Insert(tn.Index + 2, newtn);
            newtn.Parent.Nodes.Remove(tn);
            this.tvDoc.Refresh();
            this.tvDoc.SelectedNode = newtn;
            this.tvDoc.Select();
            this.OnContentChanged();
        }

        private void tsbtnCopy_Click(object sender, EventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            _CopiedXn = xn.Clone();
            _CopiedTn = (TreeNode)this.tvDoc.SelectedNode.Clone();
            this.tsbtnPaste.Enabled = true;
        }

        private void tsbtnPaste_Click(object sender, EventArgs e) {
            if (_CopiedTn != null) {
                TreeNode tn = this.tvDoc.SelectedNode;
                XmlNode xn = (XmlNode)tn.Tag;
                try {
                    xn.ParentNode.InsertAfter(_CopiedXn, xn);
                } catch (Exception ex) {
                    MessageBox.Show(ex.Message);
                    return;
                }
                tn.Parent.Nodes.Insert(tn.Index, _CopiedTn);
                _CopiedTn = null;
                _CopiedXn = null;
                this.tsbtnPaste.Enabled = false;
                this.OnContentChanged();
            }
        }

        private void tsbtnRefresh_Click(object sender, EventArgs e) {
            BindDoc2Tree();
        }

        #endregion

        private void tvDoc_AfterSelect(object sender, TreeViewEventArgs e) {
            TreeNode tn = this.tvDoc.SelectedNode;
            XmlNode xn = (XmlNode)tn.Tag;
            RefreshXmlCodeView(xn);
            SetButtonStatus(xn.Name);
        }
        
        #endregion

        private void toolStripButton1_Click(object sender, EventArgs e) {
            this.Close();
        }

        private void FrmXmlEditor_FormClosing(object sender, FormClosingEventArgs e) {
            if (_ContentChanged) {
                DialogResult dr = MessageBox.Show("有修改未保存，确定要退出吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (dr != DialogResult.Yes) {
                    e.Cancel = true;
                }
            }
        }

        private void tvDoc_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) {
            this.tsbtnEdit_Click(sender,new EventArgs());
        }

    }
}
